home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
linux-bo
/
etherboo.000
/
etherboo
/
etherboot-2.0
/
netboot-freebsd
/
linuxloader.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-01
|
9KB
|
330 lines
/**************************************************************************
Linux loader
Author: Markus Gutschke (gutschk@math.uni-muenster.de)
Date: Sep/95
**************************************************************************/
#include "netboot.h"
#define LINUX_IMAGE_ADDR ((char *)0x10000L)
#define XTRACMDS ((char *)0x98000L)
#define LINUX_BOOTSECTOR ((char *)0x90000L)
#define CMDLINEMAGIC 0xA33F
#define CMDLINE ((unsigned short *)(LINUX_BOOTSECTOR+0x20))
#define BOOTHEADER (((boot_header_t *)0x90200L)[-1])
#define SECTOR_SIZE 512
#define MAGIC 0xAA55
#define SETUP_MAGIC 0x5A5AAA55
typedef struct {
unsigned char filler;
unsigned char setup_sects;
unsigned short int root_flags;
unsigned short int syssize;
unsigned short int swap_dev;
unsigned short int ram_size;
unsigned short int vid_mode;
unsigned short int root_dev;
unsigned short int boot_flag;
} boot_header_t;
struct bootp_t bootp_reply;
char *linux_add_cmdline(char *s)
{
#ifdef NETBOOT32
if (!s) *XTRACMDS = '\000';
else if (*s) {
char *ptr = XTRACMDS;
while (*ptr) ptr++;
*ptr++ = ' ';
sprintf(ptr,"%s",s); }
return(XTRACMDS);
#endif
}
#ifdef NETBOOT32
static int strncmp(const unsigned char *s1,const unsigned char *s2,int n)
{
while (n--) {
if (*s1 != *s2) return(*s1 - *s2);
else if (!*s1) return(0);
else {s1++; s2++;}}
return(0);
}
static void linux_cmdline(char *cmdline)
{
char *s,*d,initargs = 0;
for (s = XTRACMDS; ;) { /* check for parameters to init */
if ((!*s || *s == ' ') && (initargs&1)) initargs = 2;
if (!*s) break;
if (*s == '=') {initargs &= ~1; while (*s && *s != ' ') s++;}
else if (*s++ != ' ') {
if (!(initargs&1) && !strncmp(s-1,"vga=",4)) {
int vga = 0;
d = s + 3;
if (!strncmp(d,"ASK",3)) vga = -3;
else if (!strncmp(d,"EXTENDED",8)) vga = -2;
else if (!strncmp(d,"NORMAL",6)) vga = -1;
else {
if (*d == '-') d++;
while (*d >= '0' && *d <= '9') { vga = 10*vga+*d-'0'; d++; }
if (s[3] == '-') vga = -vga; }
*((unsigned short *)(LINUX_BOOTSECTOR+506)) = vga; }
initargs |= 1; } }
for (s = nfsdiskless.root_hostnam;*s&&s[1];s++);
sprintf(cmdline,
"%sBOOT_IMAGE=%s%s%s ramdisk=0 nfsroot=%s,rsize=%d,wsize=%d,%s,%s nfsaddrs=%I:%I:%I:%I:%s %s",
initargs&2 ? "" : "auto ",
/* htonl(nfsdiskless.root_saddr.sin_addr.s_addr), */
nfsdiskless.root_hostnam,
*s == '/' ? "" : "/",
*kernel == '/' ? kernel + 1 : kernel,
nfsdiskless.root_hostnam,
nfsdiskless.root_args.rsize,
nfsdiskless.root_args.wsize,
nfsdiskless.root_args.flags & NFSMNT_SOFT ? "soft" : "hard",
nfsdiskless.root_args.flags & NFSMNT_INT ? "intr" : "nointr",
arptable[ARP_CLIENT].ipaddr,
htonl(nfsdiskless.root_saddr.sin_addr.s_addr),
arptable[ARP_GATEWAY].ipaddr,
htonl(netmask),
nfsdiskless.my_hostnam,
XTRACMDS);
for (s = d = cmdline; ;) { /* remove multiple space characters */
if (*s == ' ') {while (s[1] == ' ') s++; if (!s[1]) s++;}
if (!(*d++ = *s++)) break; }
*((unsigned short *)(LINUX_BOOTSECTOR+504)) = 0; /* no ramdisk */
*((unsigned short *)(LINUX_BOOTSECTOR+508)) = 0x00FF; /* mount root on nfs */
return;
}
#endif
int load_linux(int root_mount_port,int swap_mount_port,
int root_nfs_port,char *kernel_handle)
{
#ifdef NETBOOT32
int err, offset, read_size, count;
char *addr,*cmdline;
/* Linux boot sector and setup code has to be loaded to address 0x90000 */
if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port, kernel_handle, 0,
SECTOR_SIZE,LINUX_BOOTSECTOR)) != SECTOR_SIZE) {
readerr:
printf("Unable to read %s: ",kernel);
nfs_err(err);
bootmenu:
longjmp(jmp_bootmenu,1);
}
if (BOOTHEADER.boot_flag != MAGIC)
return(0);
/* Boot sector contains size information for setup code */
offset = SECTOR_SIZE;
read_size = SECTOR_SIZE;
count = BOOTHEADER.setup_sects;
while (count--) {
if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port, kernel_handle,
offset, read_size, LINUX_BOOTSECTOR + offset)) !=
read_size) {
if (err < 0) {
goto readerr; }
goto bootmenu; }
offset += err; }
for (count = SECTOR_SIZE-4; *(unsigned int *)(LINUX_BOOTSECTOR-
SECTOR_SIZE+offset+count) !=
SETUP_MAGIC;)
if (count-- < 0)
goto bootmenu;
/* Construct Linux's command line */
cmdline = LINUX_BOOTSECTOR + offset;
CMDLINE[0] = CMDLINEMAGIC;
CMDLINE[1] = cmdline - LINUX_BOOTSECTOR;
linux_cmdline(cmdline);
while (*cmdline) putchar(*cmdline++);
printf("\r\n");
/* Kernel image will be loaded to address 0x10000; it will automatically
be relocated to 0x100000 by the setup code */
read_size = NFS_READ_SIZE;
count = 16*BOOTHEADER.syssize;
addr = LINUX_IMAGE_ADDR;
printf("Loading compressed kernel image");
while (count >= 16) {
if (read_size > count) read_size = count;
if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port, kernel_handle,
offset, read_size, addr)) != read_size) {
if (err < 0) goto readerr;
if (read_size-err >= 16)
goto bootmenu; }
if (!(offset & 0x3C00)) putchar('.');
offset += err;
count -= err;
addr += err; }
/* Linux wants to mount swapspace and rootfilesystem by itself; so unmount */
/* all mounted NFS filesystems */
nfs_umountall(ARP_ROOTSERVER, root_mount_port);
if (arptable[ARP_SWAPSERVER].ipaddr &&
arptable[ARP_SWAPSERVER].ipaddr != arptable[ARP_ROOTSERVER].ipaddr)
nfs_umountall(ARP_SWAPSERVER, swap_mount_port);
/* Linux kernel has to be started in real-mode */
printf(" \r\nStarting...\r\n");
start_linux();
/* printf("*** %s execute failure ***\n",kernel); */
goto bootmenu;
#endif
}
/* Define some structures used by tftp loader */
union infoblock
{
unsigned short s[256];
unsigned long l[128];
struct imgheader
{
unsigned long magic;
unsigned char length;
unsigned char r[3];
struct { unsigned short bx, ds; } location;
struct { unsigned short ip, cs; } execaddr;
} i;
};
struct segheader
{
unsigned char length;
unsigned char vendortag;
unsigned char reserved;
unsigned char flags;
unsigned long loadaddr;
unsigned long imglength;
unsigned long memlength;
};
/* The following are static because linux_tftp is called for each block
and we need to retain info across calls */
static enum loadmode { Munknown, Mlinear, Mtagged } mode = Munknown;
static unsigned char segflags;
static unsigned long seglen;
static Address curaddr, last0, last1, execaddr, hdraddr, segaddr;
int linux_tftp(unsigned int block, unsigned char *data, int len)
{
int i;
if (block == 1)
{
union infoblock *ibp = (union infoblock *)data;
if (ibp->l[0] == 0x1B031336L)
{
/* the apparently unnecessary cast is to avoid a
bcc bug where the short not promoted as it should be */
segaddr = (((Address)ibp->i.location.ds) << 4) + ibp->i.location.bx;
#ifdef NETBOOT32
bcopy(data, (void *)segaddr, len);
#endif
#ifdef NETBOOT16
bcopyf(data, segaddr, len);
#endif
execaddr = ibp->l[3];
hdraddr = ibp->l[2];
last1 = last0 = segaddr + 512;
segaddr += ((ibp->i.length & 0x0F) << 2)
+ ((ibp->i.length & 0xF0) >> 2);
segflags = 0;
seglen = 0;
mode = Mtagged;
return (1);
}
else if (ibp->s[255] == 0xAA55)
{
#ifdef NETBOOT32
bcopy(data, (void *)0x7C00, len);
#endif
#ifdef NETBOOT16
bcopyf(data, 0x7C00L, len);
#endif
execaddr = hdraddr = 0x7C00000L;
curaddr = 0x10000L;
mode = Mlinear;
return (1);
}
return (0);
}
else switch (mode)
{
case Mlinear:
if (len <= 0)
{
#ifdef NETBOOT32
xstart(execaddr, hdraddr, (Address)&bootp_reply);
#endif
#ifdef NETBOOT16
xstart(execaddr, hdraddr, &bootp_reply, RELOC>>4);
#endif
longjmp(jmp_bootmenu, 1);
}
#ifdef NETBOOT32
bcopy(data, (void *)curaddr, len);
#endif
#ifdef NETBOOT16
bcopyf(data, curaddr, len);
#endif
if (curaddr += 512 >= 0x98000L)
curaddr = 0x100000L;
break;
case Mtagged:
while (seglen == 0)
{
struct segheader sh;
if (segflags & 0x04)
{
#ifdef NETBOOT32
xstart(execaddr, hdraddr, (Address)&bootp_reply);
#endif
#ifdef NETBOOT16
xstart(execaddr, hdraddr, &bootp_reply, RELOC>>4);
#endif
longjmp(jmp_bootmenu, 1);
}
#ifdef NETBOOT32
sh = *((struct segheader *)segaddr);
#endif
#ifdef NETBOOT16
fbcopy(segaddr, &sh, sizeof(struct segheader));
#endif
seglen = sh.imglength;
if ((segflags = sh.flags & 0x03) == 0)
curaddr = sh.loadaddr;
else if (segflags == 0x01)
curaddr = last1 + sh.loadaddr;
else if (segflags == 0x02)
curaddr = (Address)(memsize() * 1024L + 0x100000L)
- sh.loadaddr;
else
curaddr = last0 - sh.loadaddr;
last1 = (last0 = curaddr) + sh.memlength;
segflags = sh.flags;
segaddr += ((sh.length & 0x0F) << 2)
+ ((sh.length & 0xF0) >> 2);
}
i = (seglen > len) ? len : seglen;
#ifdef NETBOOT32
bcopy(data, (void *)curaddr, i);
#endif
#ifdef NETBOOT16
bcopyf(data, curaddr, i);
#endif
seglen -= i;
curaddr += i;
break;
case Munknown:
return (0);
}
return (1);
}